﻿using System;
using System.IO;
using SimpleServiceBus.Bus.MessageManagement;
using SimpleServiceBus.Bus.MessageManagement.Serialization;
using SimpleServiceBus.Endpoint.Metadata;
using SimpleServiceBus.Messages.Management;

namespace SimpleServiceBus.Bus.Pipeline.PipelineComponents.MessageLogging
{
    public class FlatFileMessageLogger : MessageLoggerBase
    {
        public static string _logFileBaseDirectory;
        private XmlMessageSerializer _serializer;

        /// <summary>
        /// Sets an alternate base directory for logging messages. By default,
        /// messages will be logged to a Logs subdirectory of the AppDomain.CurrentDomain.BaseDirectory
        /// This property is not thread safe, and should only be set during application initialization.
        /// </summary>
        public static string LogFileBaseDirectory
        {
            get
            {
                if (String.IsNullOrEmpty(_logFileBaseDirectory) || !Directory.Exists(_logFileBaseDirectory))
                    _logFileBaseDirectory = AppDomain.CurrentDomain.BaseDirectory;
                return _logFileBaseDirectory;
            }
        }

        protected override void PersistLogEntry(MessageLogEntry logEntry,IMessageContext messageContext,MessageLoggingLevel logLevel)
        {
            //We're going to invoke this asynchronously, as we don't need to hold up the messaging pipeline while we actually
            //write the log entry to disk.
            Action a = () =>
                           {
                               try
                               {
                                   string filePath = GetFullPathForLogEntry(logEntry, messageContext.MessagePipeline.PipelineDirection);
                                   using (var fs = new FileStream(filePath, FileMode.CreateNew, FileAccess.Write))
                                   {
                                       _serializer.Serialize(logEntry, fs);
                                       fs.Flush();
                                   }
                               }
                               catch (Exception ex)
                               {
                                   OnMessageLoggingError(messageContext,logLevel,ex);
                               }
                              
                           };
            a.BeginInvoke(null, null);
        }

        protected virtual string GetFullPathForLogEntry(MessageLogEntry logEntry,PipelineDirection pipelineDirection)
        {
            if (pipelineDirection == PipelineDirection.Receive)
                return Path.Combine(IncomingMessageLogDirectory, GetFileNameForLogEntry(logEntry));
            return Path.Combine(OutgoingMessageLogDirectory, GetFileNameForLogEntry(logEntry));
        }

        protected virtual string GetFileNameForLogEntry(MessageLogEntry logEntry)
        {
            return logEntry.MessageID + ".xml";
        }

        protected virtual string IncomingMessageLogDirectory
        {
            get { return Path.Combine(LogFileBaseDirectory, "Incoming"); }
        }

        protected virtual string OutgoingMessageLogDirectory
        {
            get { return Path.Combine(LogFileBaseDirectory, "Outgoing"); }
        }

        protected override void StartService()
        {
            if (!Directory.Exists(IncomingMessageLogDirectory))
                Directory.CreateDirectory(IncomingMessageLogDirectory);
            if (!Directory.Exists(OutgoingMessageLogDirectory))
                Directory.CreateDirectory(OutgoingMessageLogDirectory);

            _serializer = new XmlMessageSerializer {Endpoint = Endpoint};
            _serializer.Start();
            
            base.StartService();
        }

        protected override void ShutDownService()
        {
            if (_serializer.IsRunning)
                _serializer.Stop();
            base.ShutDownService();
        }
    }
}